package com.hn.zhijian.web.config.shiro;

import com.alibaba.fastjson.JSON;
import com.hn.zhijian.system.IShiroUserService;
import com.hn.zhijian.system.model.response.ResourceResponse;
import com.hn.zhijian.system.model.response.RoleResponse;
import com.hn.zhijian.system.model.response.UserResponse;
import com.hn.zhijian.utils.Utils;
import com.hn.zhijian.web.config.jwt.JwtExecute;
import com.hn.zhijian.web.config.jwt.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.List;

/**
 * Function:shiro权限控制. <br/>
 * @author carl chen
 */
@Slf4j
public class UserAuthRealm extends AuthorizingRealm {


    @Autowired
    private JwtExecute jwtExecute;

    @Autowired
    private IShiroUserService shiroUserService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
        String token;
        if(authToken instanceof UsernamePasswordToken){
            //账号密码登录验证
             token = ((UsernamePasswordToken) authToken).getUsername();
        }else{
            token = jwtExecute.getUsername(authToken.getCredentials().toString());
        }
        UserResponse user = shiroUserService.getUser(token);
        if (user != null) {
            SimpleAuthenticationInfo authInfo = new SimpleAuthenticationInfo(user, token, user.getUsername());
            return authInfo;
        } else {
            throw new ExcessiveAttemptsException();
        }
    }


    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();

        if(Utils.isEmpty(username)){
            username = jwtExecute.getUsername(principals.toString());
        }
//        String username = JwtUtil.getUsername(principals.toString());
        /**
         * 把principals放session中 key=userId value=principals
         */
        SimpleAuthorizationInfo info = this.authorize(username);
        return info;
    }

    /**
     * 设置用户session
     */
//    private void initSession(SysUser user) {
//        Session session = SecurityUtils.getSubject().getSession();
//
//        session.setTimeout(-1000L);// timeout:-1000ms 永不超时
//
//        UserResponse userResponse = BeanCopier.copyJSONObject(user, UserResponse.class);
//
//        session.setAttribute(Const.SESSION_USER, userResponse);
//    }

    /**
     * 为用户授权.
     *
     * @param username
     * @return
     */
    private SimpleAuthorizationInfo authorize(String username) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        /**
         * 赋予角色
         */
        List<RoleResponse> roles = shiroUserService.getRole(username);
        for (RoleResponse role : roles) {
            if (role != null) {
                info.addRole(role.getCode());
            }
        }

        /**
         * 赋予权限
         */
        List<ResourceResponse> permissions = shiroUserService.getRoleAuthority(username);
        for (ResourceResponse permission : permissions) {
            if (permission != null && StringUtils.isNotEmpty(permission.getCode())) {
                info.addStringPermission(permission.getCode());
            }
        }
        log.info("roles:" + JSON.toJSONString(info.getRoles()));
        log.info("permission:" + JSON.toJSONString(info.getStringPermissions()));
        return info;
    }

    /**
     * 设定Password校验.
     * 自定义密码验证
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        setCredentialsMatcher(new CustomizedCredentialsMatcher(jwtExecute));
    }

    @Override
    public CredentialsMatcher getCredentialsMatcher() {
        return super.getCredentialsMatcher();
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        this.clearAllCachedAuthenticationInfo();
        this.clearAllCachedAuthorizationInfo();
    }
}
